from machine import reset, Pin
from time import sleep, ticks_ms
import usocket as socket
import gc
import network
import camera

# 摄像头配置常量
PIN_PWDN    = const(0)
PIN_RESET   = const(1)
PIN_XCLK    = const(2)
PIN_SIOD    = const(3)
PIN_SIOC    = const(4)
PIN_D7      = const(5)
PIN_D6      = const(6)
PIN_D5      = const(7)
PIN_D4      = const(8)
PIN_D3      = const(9)
PIN_D2      = const(10)
PIN_D1      = const(11)
PIN_D0      = const(12)
PIN_VSYNC   = const(13)
PIN_HREF    = const(14)
PIN_PCLK    = const(15)
XCLK_MHZ    = const(16)
PIXFORMAT   = const(17)
FRAMESIZE   = const(18)
JPEG_QUALITY= const(19)
FB_COUNT    = const(20)

# ESP32-S3 摄像头配置（针对S3优化的引脚定义）
esp32s3_cam = {
    PIN_PWDN: 32,
    PIN_RESET: -1,
    PIN_XCLK: 0,
    PIN_SIOD: 26,
    PIN_SIOC: 27,
    PIN_D7: 35,
    PIN_D6: 34,
    PIN_D5: 39,
    PIN_D4: 36,
    PIN_D3: 21,
    PIN_D2: 19,
    PIN_D1: 18,
    PIN_D0: 5,
    PIN_VSYNC: 25,
    PIN_HREF: 23,
    PIN_PCLK: 22,
    XCLK_MHZ: 16,
    PIXFORMAT: 3,  # 使用JPEG格式
    FRAMESIZE: 10,  # VGA分辨率(640x480)
    JPEG_QUALITY: 10,
    FB_COUNT: 1, 
}

# HTML和HTTP头定义
pg = {
    'foto':'''<!DOCTYPE html>
<html>
<head>
<title>ESP32-S3 Camera Stream</title>
<style>
    body { margin: 0; padding: 20px; background-color: #f0f0f0; }
    .container { max-width: 1200px; margin: 0 auto; }
    h1 { color: #333; text-align: center; }
    .stream-container { text-align: center; margin: 20px 0; }
    #stream { max-width: 100%; border: 5px solid #333; border-radius: 5px; }
    .status-box { background-color: #fff; padding: 15px; border-radius: 5px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
</style>
</head>
<body>
    <div class="container">
        <h1>ESP32-S3 实时视频流</h1>
        <div class="stream-container">
            <img id="stream" src="/live" alt="实时视频流">
        </div>
        <div class="status-box">
            <p>服务器状态: <span id="server-status">连接中...</span></p>
            <p>帧率: <span id="fps">0</span> FPS</p>
            <p>分辨率: 640x480</p>
        </div>
    </div>
</body>
</html>
''',
}

hdr = {
    'foto': """HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Connection: Closed
Content-Length: %d""",
    'stream': """HTTP/1.1 200 OK
Content-Type: multipart/x-mixed-replace; boundary=frame
Connection: keep-alive
Cache-Control: no-cache
Pragma: no-cache""",
    'frame': """--frame
Content-Type: image/jpeg
Content-Length: %d""",
}

# WiFi配置
class Sta:
    AP = "LAPTOP-D3RPTUAA 6358"  # WiFi名称
    PWD = "19234949992.ch"       # WiFi密码

    def __init__(self, ap='', pwd=''):
        network.WLAN(network.AP_IF).active(False)  # 禁用接入点模式
        self.wlan = network.WLAN(network.STA_IF)
        self.wlan.active(True)
        if ap:
            self.ap = ap
            self.pwd = pwd
        else:
            self.ap = Sta.AP
            self.pwd = Sta.PWD

    def connect(self):
        if not self.wlan.isconnected():
            print(f"连接到 {self.ap}...")
            self.wlan.connect(self.ap, self.pwd)

    def wait(self):
        cnt = 30
        while cnt > 0 and not self.wlan.isconnected():
            print(f"等待WiFi连接...({cnt})")
            sleep(1)
            cnt -= 1
        if self.wlan.isconnected():
            print("WiFi已连接")
            print('网络配置:', self.wlan.ifconfig())
            return self.wlan.ifconfig()[0]
        else:
            print("WiFi连接失败")
            return None

# 服务器和路由处理
ip = ''
camera_instance = None

# 视频流状态跟踪
stream_stats = {
    'total_frames': 0,
    'total_bytes': 0,
    'start_time': 0,
    'last_stats_time': 0,
    'last_fps_calc': 0,
    'fps_frames': 0,
    'current_fps': 0
}

def clean_up(cs):
    try:
        cs.close()
    except:
        pass
    del cs
    gc.collect()

def handle_root(cs):
    """处理根路径请求，返回HTML页面"""
    p = pg['foto']
    ln = len(p) + 2
    response = f"{hdr['foto'] % ln}\r\n\r\n{p}\r\n"
    cs.write(response.encode())

def handle_live(cs):
    """处理视频流请求，发送MJPEG流并打印状态"""
    global stream_stats
    
    # 发送MJPEG流头部
    cs.write(f"{hdr['stream']}\r\n\r\n".encode())
    cs.setblocking(True)
    
    # 初始化流统计
    if stream_stats['start_time'] == 0:
        stream_stats['start_time'] = ticks_ms()
        stream_stats['last_stats_time'] = ticks_ms()
        stream_stats['last_fps_calc'] = ticks_ms()
    
    print("开始视频流传输...")
    
    try:
        while True:
            # 捕获图像
            frame = camera_instance.capture()
            frame_size = len(frame)
            
            # 更新统计信息
            stream_stats['total_frames'] += 1
            stream_stats['total_bytes'] += frame_size
            stream_stats['fps_frames'] += 1
            
            # 计算FPS（每秒钟）
            current_time = ticks_ms()
            if current_time - stream_stats['last_fps_calc'] >= 1000:
                elapsed = (current_time - stream_stats['last_fps_calc']) / 1000
                stream_stats['current_fps'] = int(stream_stats['fps_frames'] / elapsed)
                stream_stats['fps_frames'] = 0
                stream_stats['last_fps_calc'] = current_time
            
            # 每5秒打印一次状态
            if current_time - stream_stats['last_stats_time'] >= 5000:
                elapsed_total = (current_time - stream_stats['start_time']) / 1000
                avg_fps = stream_stats['total_frames'] / elapsed_total
                total_mb = stream_stats['total_bytes'] / (1024 * 1024)
                avg_frame_kb = stream_stats['total_bytes'] / stream_stats['total_frames'] / 1024
                
                print("\n===== 视频流状态 =====")
                print(f"总帧数: {stream_stats['total_frames']}")
                print(f"当前FPS: {stream_stats['current_fps']}")
                print(f"平均FPS: {avg_fps:.1f}")
                print(f"总传输数据: {total_mb:.2f} MB")
                print(f"平均帧大小: {avg_frame_kb:.1f} KB")
                print(f"运行时间: {elapsed_total:.1f} 秒")
                print("======================\n")
                
                stream_stats['last_stats_time'] = current_time
            
            # 发送一帧图像
            try:
                cs.write(f"{hdr['frame'] % frame_size}\r\n\r\n".encode())
                cs.write(frame)
                cs.write(b"\r\n")
            except Exception as e:
                print(f"发送帧时出错: {e}")
                break
            
            # 短暂延迟，控制帧率
            sleep(0.05)  # 控制在约20FPS
            
    except Exception as e:
        print(f"视频流错误: {e}")
    finally:
        print(f"视频流结束 - 共发送 {stream_stats['total_frames']} 帧")
        clean_up(cs)

def route(cs, path):
    """路由处理函数"""
    if path == '/' or path == '/webcam':
        handle_root(cs)
    elif path == '/live':
        handle_live(cs)
    else:
        cs.write(b'HTTP/1.1 404 Not Found\r\n\r\n')
        clean_up(cs)

def start_server(port=80):
    """启动HTTP服务器"""
    global ip
    try:
        ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        ss.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        ss.bind(('0.0.0.0', port))
        ss.listen(1)
        print(f"服务器启动在端口 {port}")
        print(f"请在浏览器中访问: http://{ip}")

        while True:
            cs, ca = ss.accept()
            cs.settimeout(10.0)
            try:
                r = cs.recv(1024)
                if r:
                    ms = r.decode()
                    rq = ms.split(' ')
                    if len(rq) >= 2:
                        path = rq[1]
                        print(f"收到请求: {path} 来自 {ca}")
                        route(cs, path)
            except Exception as e:
                print(f"请求处理错误: {e}")
            finally:
                clean_up(cs)
    except Exception as e:
        print(f"服务器启动错误: {e}")
        reset()

# 主程序初始化
def main():
    global ip, camera_instance
    gc.enable()
    gc.collect()

    # 配置摄像头
    def configure_camera(cam, config):
        for key, val in config.items():
            cam.conf(key, val)

    # 配置ESP32-S3摄像头
    configure_camera(camera, esp32s3_cam)
    camera.conf(XCLK_MHZ, 16)

    # 初始化摄像头
    cam_ready = False
    for i in range(5):
        try:
            cam_ready = camera.init()
            print(f"摄像头初始化尝试 {i+1}/5: {'成功' if cam_ready else '失败'}")
            if cam_ready:
                break
        except Exception as e:
            print(f"摄像头初始化错误: {e}")
        sleep(2)
    
    if not cam_ready:
        print("摄像头初始化失败，重启设备...")
        sleep(2)
        reset()

    # 配置摄像头参数
    camera.framesize(10)                # 640x480分辨率
    camera.quality(30)                  # 图像质量(0-63，值越小质量越高)
    camera.brightness(0)                # 亮度(-2至2)
    camera.contrast(0)                  # 对比度(-2至2)
    camera.saturation(0)                # 饱和度(-2至2)
    camera.speffect(camera.EFFECT_NONE) # 无特效
    camera.whitebalance(camera.WB_AUTO) # 自动白平衡
    camera.flip(0)                      # 不翻转
    camera.mirror(0)                    # 不镜像
    camera_instance = camera

    print("摄像头配置完成")

    # 连接WiFi
    w = Sta()
    w.connect()
    ip = w.wait()
    if not ip:
        print("WiFi连接失败，重启设备...")
        sleep(2)
        reset()

    # 启动服务器
    start_server()

if __name__ == "__main__":
    main()
